/**
 * 添加文本向量（带元信息）
 *
 * @param {string} key - 向量的唯一标识符
 *
 * @param {string} role - 向量所属的角色（如用户、助手）
 *
 * @param {string} content - 向量对应的原始文本内容
 *
 * @param {number[]} embedding - 向量的嵌入表示（如OpenAI的嵌入向量）
 *
 * @param {number} start - 原始文本中向量开始的位置索引（默认为0）
 *
 * @param {number} end - 原始文本中向量结束的位置索引（默认为内容长度）
 */
function vectorAdd(key, role, content, embedding, start = 0, end = content.length) {
    // 检查向量存储是否超过最大大小，若超过则移除最早的条目直到保留最大大小
    while (vectorStore.size >= VECTOR_STORE_MAX_SIZE) {
        /** 获取并删除第一个键值对（最早添加的） */
        const firstKey = vectorStore.keys().next().value;
        // 确保 firstKey 存在，避免删除 undefined 键
        if (firstKey) vectorStore.delete(firstKey);
    }
    // 存储新向量
    vectorStore.set(key, { role, content, embedding, start, end });
}

/**
 * 添加知识库向量
 *
 * @param {string} key - 知识库向量的唯一标识符
 *
 * @param {string} message - 知识库文件中的原始文本内容
 *
 * @param {number[]} vector - 知识库文件内容的嵌入向量表示
 *
 * @param {string} timestamp - 知识库文件内容的创建或更新时间戳
 */
function vectorAddKnowledge(key, message, vector, timestamp) {
    // 检查向量存储是否超过最大大小，若超过则移除最早的条目直到保留最大大小
    while (knowledgeVectorStore.size >= VECTOR_STORE_MAX_SIZE) {
        /** 获取并删除第一个键值对（最早添加的） */
        const firstKey = knowledgeVectorStore.keys().next().value;
        // 确保 firstKey 存在，避免删除 undefined 键
        if (firstKey) knowledgeVectorStore.delete(firstKey);
    }
    // 存储新知识库向量
    knowledgeVectorStore.set(key, { message, vector, timestamp });
}

/**
 * 删除向量
 *
 * @param {string} key - 向量的唯一标识符
 */
function vectorDelete(key) {
    // 删除核心向量中的对应项
    vectorStore.delete(key);
    // 删除知识库向量中的对应项
    knowledgeVectorStore.delete(key);
}

/**
 * 清空数据库
 */
function vectorClear() {
    // 清空对话历史向量
    vectorStore.clear();
    // 清空知识库向量
    knowledgeVectorStore.clear();
}

/**
 * 计算两个向量的余弦相似度
 *
 * 余弦相似度用于衡量两个向量方向的相似性，取值范围为 -1 到 1，值越接近 1 表示越相似
 *
 * @param {number[]} a - 第一个向量
 *
 * @param {number[]} b - 第二个向量
 *
 * @returns {number} 两个向量的余弦相似度，如果分母为 0 则返回 0
 */
function vectorCosineSimilarity(a, b) {
    // 检查两个向量的长度是否相同，不同则抛出错误
    if (a.length !== b.length) throw new Error("向量长度必须相同");
    // 初始化点积和两个向量的模
    let dot = 0, magA = 0, magB = 0;
    // 遍历向量元素，计算点积和两个向量的模的平方和
    for (let i = 0; i < a.length; i++) {
        // 计算点积：对应元素相乘后累加
        dot += a[i] * b[i];
        // 计算向量 a 的模的平方和
        magA += a[i] ** 2;
        // 计算向量 b 的模的平方和
        magB += b[i] ** 2;
    }
    /** 计算两个向量模的乘积 */
    const magProduct = Math.sqrt(magA) * Math.sqrt(magB);
    // 如果模的乘积为 0，直接返回 0，避免除零错误；否则返回余弦相似度
    return magProduct === 0 ? 0 : dot / magProduct;
}

/**
 * 查询与给定嵌入向量最相似的前 topK 个向量
 *
 * @param {number[]} queryEmbedding - 用于查询的嵌入向量
 *
 * @param {number} topK - 返回的最相似向量的数量，默认为 vectorDefaultTopK
 *
 * @returns {Promise<Array<{ key: string, role: string, content: string, score: number }>>} - 包含最相似向量信息的数组
 */
async function vectorQuery(queryEmbedding, topK = vectorDefaultTopK) {
    /** 存储所有向量的相似度得分 */
    const scores = [];
    // 遍历核心向量存储，计算每个向量与查询向量的余弦相似度
    for (const [key, item] of vectorStore) {
        /** 计算当前向量与查询向量的余弦相似度 */
        const score = vectorCosineSimilarity(item.embedding, queryEmbedding);
        // 将相似度得分及相关信息添加到 scores 数组中
        scores.push({ key, role: item.role, content: item.content, score });
    }
    // 遍历知识库向量存储，计算每个向量与查询向量的余弦相似度
    for (const [key, item] of knowledgeVectorStore) {
        /** 计算当前向量与查询向量的余弦相似度 */
        const score = vectorCosineSimilarity(item.vector, queryEmbedding);
        // 将相似度得分及相关信息添加到 scores 数组中，角色固定为 "knowledge"
        scores.push({ key, role: "knowledge", content: item.message, score });
    }
    // 按相似度得分降序排序，取前 topK 个结果，再反转以升序返回
    return scores.sort((a, b) => b.score - a.score).slice(0, topK).reverse();
};

/**
 * 查询向量上下文，结合对话历史获取相关信息
 *
 * 如果向量嵌入功能不可用或过程中出现错误，将调用回退策略
 *
 * @returns {Promise<Array<{ role: string, content: string }>>} 返回包含角色和内容的消息数组
 */
async function vectorQueryContext() {
    // 检查向量嵌入功能是否可用，不可用则调用回退策略
    if (!vectorAllowEmbedding) return vectorFallbackStrategy();
    try {
        /** 过滤对话历史，仅保留有实际内容的消息 */
        const history = conversationHistory.filter(msg => msg.content && msg.content.trim().length !== 0);
        // 如果对话历史为空，调用回退策略
        if (history.length === 0) return vectorFallbackStrategy();
        /** 初始化最后一条用户消息和最后一条助手消息 */
        let [lastUser, lastAssistant] = [null, null];
        // 从最新消息开始遍历，找到最后一条用户消息和最后一条助手消息
        for (let i = history.length - 1; i >= 0; i--) {
            // 找到最后一条用户消息
            if (!lastUser && history[i].role === "user") lastUser = history[i];
            // 找到最后一条助手消息
            else if (!lastAssistant && history[i].role === "assistant") lastAssistant = history[i];
            // 若已找到最后一条用户消息和最后一条助手消息，停止遍历
            if (lastUser && lastAssistant) break;
        }
        // 如果没有找到用户消息，调用回退策略
        if (!lastUser) return vectorFallbackStrategy();
        // 同步向量存储与对话历史
        vectorSyncWithHistory(history);
        // 为对话历史中的新消息添加向量嵌入
        await vectorAddNewEmbeddings(history);
        /** 获取最后一条用户消息的向量嵌入 */
        const queryEmbed = (await vectorGetEmbedding(lastUser.content))[0];
        /** 查询与用户消息最相似的 topK 条结果 */
        const relatedResults = await vectorQuery(queryEmbed, vectorDefaultTopK);
        /** 用于记录已经处理过的内容，避免重复 */
        const seen = new Set();
        /** 筛选出合适的消息 */
        const messages = [];
        // 遍历查询结果，筛选出合适的消息
        for (const item of relatedResults) {
            /** 提取消息内容 */
            const content = item.content;
            // 如果内容为空或已经处理过，跳过当前结果
            if (!content || seen.has(content)) continue;
            // 如果内容与最后一条用户消息或最后一条助手消息相同，跳过当前结果
            if (content === lastUser.content || content === lastAssistant?.content) continue;
            // 记录已处理内容
            seen.add(content);
            // 保存消息内容
            messages.push({ role: item.role, content });
        };
        /** 初始化最终上下文，包含筛选出的消息 */
        const finalContext = [...messages];
        // 如果存在最后一条助手消息，添加到最终上下文中
        if (lastAssistant) finalContext.push(lastAssistant);
        // 将最后一条用户消息添加到最终上下文中
        finalContext.push(lastUser);
        // 返回最终上下文，确保每条消息都包含角色和内容
        return finalContext.map(msg => ({ role: msg.role, content: msg.content }));
    }
    catch (error) {
        // 捕获异常并显示错误信息
        showSystemMessage(`${error.name} | ${error.message} | ${error.stack}`, "error");
        // 禁用向量嵌入功能
        vectorAllowEmbedding = false;
        // 调用回退策略
        return vectorFallbackStrategy();
    }
};